#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"

namespace tcp
{

class tcp_client
{
public:
    tcp_client(std::string sip, uint16_t sport) : _sock(0), _sip(sip), _sport(sport)
    {}

    ~tcp_client()
    {
        close(_sock);
    }

    void init()
    {
        // 1. socket
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0) 
        {
            std::cerr << "socket error" << std::endl;
            exit(SOCKET_ERR);
        }
        std::cout << "socket success " << _sock << std::endl;

        // 2. connect
        struct sockaddr_in peer;
        memset(&peer, 0, sizeof(peer));
        peer.sin_family = AF_INET;
        peer.sin_port = htons(_sport);
        inet_aton(_sip.c_str(), &peer.sin_addr);

        int cnt = 5;
        while (connect(_sock, (struct sockaddr*)&peer, sizeof(peer)) < 0)
        {
            std::cerr << "connect failed, remaining try " << cnt-- << std::endl;
            if (cnt == 0)
            {
                std::cerr << "connect error" << std::endl;
                exit(CONNECT_ERR);
            }
            sleep(1);
        }
        std::cout << "connect success" << std::endl;
    }

    void start()
    {
        while (true)
        {
            std::string msg;
            std::cout << "please input:> ";
            getline(std::cin, msg);

            send(_sock, msg.c_str(), msg.size(), 0);

            char buf[1024] = {0};
            ssize_t s = recv(_sock, buf, sizeof(buf), 0);
            if (s > 0)
            {
                buf[s] = 0;
                std::cout << "server return " << buf << std::endl;
            }
            else if (s == 0)
            {
                close(_sock);
                std::cout << "server quit" << std::endl;
                break;
            }
            else
            {
                close(_sock);
                std::cerr << "recv error " << strerror(errno) << std::endl;
                break;
            }

        }
    }

private:
    int _sock;
    std::string _sip;
    uint16_t _sport;
};

}

